package com.tsfyun.scm.service.impl.materiel;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tsfyun.common.base.dto.Result;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.security.SecurityUtil;
import com.tsfyun.common.base.util.ResultUtil;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.scm.client.CustomsCodeClient;
import com.tsfyun.scm.dto.materiel.NameElementsDTO;
import com.tsfyun.scm.dto.materiel.NameElementsQTO;
import com.tsfyun.scm.entity.materiel.NameElements;
import com.tsfyun.scm.mapper.materiel.NameElementsMapper;
import com.tsfyun.scm.service.materiel.INameElementsService;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.system.vo.CustomsCodeVO;
import com.tsfyun.scm.system.vo.CustomsElementsVO;
import com.tsfyun.scm.vo.materiel.NameElementsPlusVO;
import com.tsfyun.scm.vo.materiel.NameElementsVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.WeekendSqls;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 品名要素 服务实现类
 * </p>
 *

 * @since 2020-03-26
 */
@Service
public class NameElementsServiceImpl extends ServiceImpl<NameElements> implements INameElementsService {

    @Autowired
    private CustomsCodeClient customsCodeClient;

    @Autowired
    private NameElementsMapper nameElementsMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(NameElementsDTO dto) {
        //校验海关编码是否正确
        Result<CustomsCodeVO> customsCodeVOResult = customsCodeClient.detail(dto.getHsCode());
        ResultUtil.checkRemoteResult(customsCodeVOResult,"获取海关编码数据异常，请您稍后再试");
        TsfPreconditions.checkArgument(Objects.nonNull(customsCodeVOResult.getData()),new ServiceException("海关编码填写错误"));
        NameElements nameElements = new NameElements();
        nameElements.setId(StringUtils.uuid());
        nameElements.setNameMemo(dto.getNameMemo());
        nameElements.setName(dto.getName());
        nameElements.setHsCode(dto.getHsCode());
        if(CollUtil.isNotEmpty(dto.getElementsVal())) {
            nameElements.setElements(String.join("|", dto.getElementsVal()));
        }
        nameElements.setDisabled(Boolean.FALSE);
        nameElements.setDateCreated(LocalDateTime.now());
        nameElements.setLastUpdated(nameElements.getDateCreated());
        nameElements.setCreatePerson(SecurityUtil.getCurrentPersonIdAndName());
        nameElements.setUpdatePerson(nameElements.getCreatePerson());
        try {
            super.saveNonNull(nameElements);
        } catch (DuplicateKeyException e) {
            if(e.getMessage().contains("Uni_name_memo")) {
                throw new ServiceException("要素名称已经存在");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(NameElementsDTO dto) {
        NameElements nameElements = super.getById(dto.getId());
        TsfPreconditions.checkArgument(Objects.nonNull(nameElements),new ServiceException("品名要素数据不存在"));
        //校验海关编码是否正确
        Result<CustomsCodeVO> customsCodeVOResult = customsCodeClient.detail(dto.getHsCode());
        ResultUtil.checkRemoteResult(customsCodeVOResult,"获取海关编码数据异常，请您稍后再试");
        TsfPreconditions.checkArgument(Objects.nonNull(customsCodeVOResult.getData()),new ServiceException("海关编码填写错误"));
        nameElements.setNameMemo(dto.getNameMemo());
        nameElements.setName(dto.getName());
        nameElements.setHsCode(dto.getHsCode());
        if(CollUtil.isNotEmpty(dto.getElementsVal())) {
            nameElements.setElements(String.join("|", dto.getElementsVal()));
        } else {
            nameElements.setElements(null);
        }
        nameElements.setLastUpdated(nameElements.getDateCreated());
        nameElements.setUpdatePerson(SecurityUtil.getCurrentPersonIdAndName());
        try {
            super.updateById(nameElements);
        } catch (DuplicateKeyException e) {
            if(e.getMessage().contains("Uni_name_memo")) {
                throw new ServiceException("要素名称已经存在");
            }
        }
    }

    @Override
    public PageInfo<NameElementsVO> pageList(NameElementsQTO qto) {
        PageHelper.startPage(qto.getPage(),qto.getLimit());
        List<NameElementsVO> list = nameElementsMapper.list(qto);
        //获取海关编码数据
        Map<String,CustomsCodeVO> customsCodeVOMap = Maps.newHashMap();
        //海关编码去重
        List<String> hsCodes = list.stream().map(NameElementsVO::getHsCode).distinct().collect(Collectors.toList());
        hsCodes.stream().forEach(hsCode->{
            Result<CustomsCodeVO> customsCodeVOResult = customsCodeClient.detail(hsCode);
            //此处不报错，最多仅仅影响分页列表的显示，因为即使没显示，前端还可以单独调用接口获取数据
            customsCodeVOMap.put(hsCode,customsCodeVOResult.isSuccess() ? customsCodeVOResult.getData() : null);
        });
        list.stream().forEach(nameElementsVO -> {
            CustomsCodeVO customsCodeVO = customsCodeVOMap.get(nameElementsVO.getHsCode());
            nameElementsVO.buildCustomsCode(customsCodeVO);
        });
        return new PageInfo<>(list);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteBatch(List<String> ids) {
       TsfPreconditions.checkArgument(CollUtil.isNotEmpty(ids),new ServiceException("请您至少选择一条数据"));
        try {
            super.removeByIds(ids);
            //防止有外键关联
        } catch (DataIntegrityViolationException e) {
            throw new ServiceException("待删除的数据存在关联性数据，请勿操作");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateDisabled(String id, Boolean disabled) {
        NameElements nameElements = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(nameElements),new ServiceException("数据不存在"));

        NameElements update = new NameElements();
        update.setDisabled(disabled);
        nameElementsMapper.updateByExampleSelective(update, Example.builder(NameElements.class).where(
                WeekendSqls.<NameElements>custom().andEqualTo(NameElements::getId, id)).build()
        );
    }

    @Override
    public NameElementsPlusVO detail(String id,boolean isGetCustomsElements) {
        NameElements nameElements = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(nameElements),new ServiceException("数据不存在"));
        NameElementsVO nameElementsVO = beanMapper.map(nameElements,NameElementsVO.class);
        List elementValues = Lists.newArrayList();
        if(StringUtils.isNotEmpty(nameElements.getElements())){
            String declareSpec = StringUtils.removeSpecialSymbol(nameElements.getElements());
            //最后一位是|
            if(StringUtils.isNotEmpty(declareSpec)
                    && declareSpec.lastIndexOf("|") == (declareSpec.length()-1)){
                declareSpec += " ";
            }
            elementValues = Arrays.asList(declareSpec.split("\\|"));
        }
        Result<CustomsCodeVO> customsCodeVOResult = customsCodeClient.detail(nameElements.getHsCode());
        //此处不报错，最多仅仅影响分页列表的显示，因为即使没显示，前端还可以单独调用接口获取数据
        nameElementsVO.setHsCodeName(customsCodeVOResult.isSuccess() && Objects.nonNull(customsCodeVOResult.getData()) ? customsCodeVOResult.getData().getName() : null);
        if(isGetCustomsElements) {
            //获取申报要素信息
            Result<List<CustomsElementsVO>> elementsResult = customsCodeClient.elementDetail(nameElements.getHsCode());
            //如果获取失败报错，防止修改页面调用进入然后获取不到数据提交
            ResultUtil.checkRemoteResult(elementsResult, "获取申报要素数据异常，请您稍后再试");
            return new NameElementsPlusVO(nameElementsVO,elementValues,elementsResult.getData());
        }
        return new NameElementsPlusVO(nameElementsVO,elementValues,null);
    }
}
